home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / timidsrc.zip / win_a.c < prev   
C/C++ Source or Header  |  1996-05-20  |  5KB  |  250 lines

  1. /*
  2.  
  3.     TiMidity -- Experimental MIDI to WAVE converter
  4.     Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.     
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.     
  20.     win_audio.c
  21.     
  22.     Functions to play sound on the Win32 audio driver (Win 95 or Win NT).
  23.  
  24. */
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <windows.h>
  30.  
  31. #include "config.h"
  32. #include "output.h"
  33. #include "controls.h"
  34.  
  35. static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
  36. static void close_output(void);
  37. static void output_data(int32 *buf, int32 count);
  38. static void flush_output(void);
  39. static void purge_output(void);
  40.  
  41. /* export the playback mode */
  42.  
  43. #define dpm win32_play_mode
  44.  
  45. PlayMode dpm = {
  46.   DEFAULT_RATE, PE_16BIT|PE_SIGNED,
  47.   -1,
  48.   {16},
  49.   "Win32 audio driver", 'd',
  50.   NULL,
  51.   open_output,
  52.   close_output,
  53.   output_data,
  54.   flush_output,
  55.   purge_output
  56. };
  57.  
  58. /* Max audio blocks waiting to be played */
  59.  
  60. static LPHWAVEOUT dev;
  61. static int nBlocks;
  62.  
  63. extern CRITICAL_SECTION critSect;
  64.  
  65. static void wait (void)
  66.     {
  67.     while (nBlocks)
  68.         Sleep (0);
  69.     }
  70.  
  71. static int play (void *mem, int len)
  72.     {
  73.     HGLOBAL hg;
  74.     LPWAVEHDR wh;
  75.     MMRESULT res;
  76.  
  77.     while (nBlocks >= dpm.extra_param[0])
  78.         Sleep (0);
  79.  
  80.     hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (WAVEHDR));
  81.     if (!hg)
  82.         {
  83.         ctl->cmsg (CMSG_INFO, VERB_NORMAL, "GlobalAlloc failed!");
  84.         return FALSE;
  85.         }
  86.     wh = GlobalLock (hg);
  87.     wh->dwBufferLength = len;
  88.     wh->lpData = mem;
  89.  
  90.     res = waveOutPrepareHeader (dev, wh, sizeof (WAVEHDR));
  91.     if (res)
  92.         {
  93.         ctl->cmsg (CMSG_INFO, VERB_NORMAL, "waveOutPrepareHeader: %d", res);
  94.         GlobalUnlock (hg);
  95.         GlobalFree (hg);
  96.         return TRUE;
  97.         }
  98.     res = waveOutWrite (dev, wh, sizeof (WAVEHDR));
  99.     if (res)
  100.         {
  101.         ctl->cmsg (CMSG_INFO, VERB_NORMAL, "waveOutWrite: %d", res);
  102.         GlobalUnlock (hg);
  103.         GlobalFree (hg);
  104.         return TRUE;
  105.         }
  106.     EnterCriticalSection (&critSect);
  107.     nBlocks++;
  108.     LeaveCriticalSection (&critSect);
  109. //    cmsg (CMSG_INFO,VERB_NOISY, "Play: %d blocks", nBlocks);
  110.     return FALSE;
  111.     }
  112.  
  113. #pragma argsused
  114. static void CALLBACK wave_callback (HWAVE hWave, UINT uMsg,
  115.         DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
  116.     {
  117.     WAVEHDR *wh;
  118.     HGLOBAL hg;
  119.  
  120.     if (uMsg == WOM_DONE)
  121.         {
  122.         EnterCriticalSection (&critSect);
  123.         wh = (WAVEHDR *)dwParam1;
  124.         waveOutUnprepareHeader (dev, wh, sizeof (WAVEHDR));
  125.         hg = GlobalHandle (wh->lpData);
  126.         GlobalUnlock (hg);
  127.         GlobalFree (hg);
  128.         hg = GlobalHandle (wh);
  129.         GlobalUnlock (hg);
  130.         GlobalFree (hg);
  131.         nBlocks--;
  132.         LeaveCriticalSection (&critSect);
  133. //        cmsg (CMSG_INFO, VERB_NOISY, "Callback: %d blocks", nBlocks);
  134.         }
  135.     }
  136.  
  137. static int open_output (void)
  138.     {
  139.     int i, j, mono, eight_bit, warnings = 0;
  140.     PCMWAVEFORMAT pcm;
  141.     MMRESULT res;
  142.  
  143.     /* Check if there is at least one audio device */
  144.     if (!waveOutGetNumDevs ())
  145.         {
  146.         ctl->cmsg (CMSG_ERROR, VERB_NORMAL, "No audio devices present!");
  147.         return -1;
  148.         }
  149.  
  150.     /* They can't mean these */
  151.     dpm.encoding &= ~(PE_ULAW|PE_BYTESWAP);
  152.  
  153.     if (dpm.encoding & PE_16BIT)
  154.         dpm.encoding |= PE_SIGNED;
  155.     else
  156.         dpm.encoding &= ~PE_SIGNED;
  157.  
  158.     mono = (dpm.encoding & PE_MONO);
  159.     eight_bit = !(dpm.encoding & PE_16BIT);
  160.  
  161.     pcm.wf.wFormatTag = WAVE_FORMAT_PCM;
  162.     pcm.wf.nChannels = mono ? 1 : 2;
  163.     pcm.wf.nSamplesPerSec = i = dpm.rate;
  164.     j = 1;
  165.     if (!mono)
  166.         {
  167.         i *= 2;
  168.         j *= 2;
  169.         }
  170.     if (!eight_bit)
  171.         {
  172.         i *= 2;
  173.         j *= 2;
  174.         }
  175.     pcm.wf.nAvgBytesPerSec = i;
  176.     pcm.wf.nBlockAlign = j;
  177.     pcm.wBitsPerSample = eight_bit ? 8 : 16;
  178.  
  179.     res = waveOutOpen (NULL, 0, (LPWAVEFORMAT)&pcm, NULL, 0, WAVE_FORMAT_QUERY);
  180.     if (res)
  181.         {
  182.         ctl->cmsg (CMSG_ERROR, VERB_NORMAL, "Format not supported!");
  183.         return -1;
  184.         }
  185.     res = waveOutOpen (&dev, 0, (LPWAVEFORMAT)&pcm, (DWORD)wave_callback, 0, CALLBACK_FUNCTION);
  186.     if (res)
  187.         {
  188.         ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Can't open audio device");
  189.         return -1;
  190.         }
  191.     nBlocks = 0;
  192.     return warnings;
  193.     }
  194.  
  195. static void output_data (int32 *buf, int32 count)
  196.     {
  197.     int len = count;
  198.     HGLOBAL hg;
  199.     void *b;
  200.  
  201.     if (!(dpm.encoding & PE_MONO)) /* Stereo sample */
  202.         {
  203.         count *= 2;
  204.         len *= 2;
  205.         }
  206.  
  207.     if (dpm.encoding & PE_16BIT)
  208.         len *= 2;
  209.  
  210.     hg = GlobalAlloc (GMEM_MOVEABLE, len);
  211.     if (!hg)
  212.         {
  213.         ctl->cmsg (CMSG_INFO, VERB_NORMAL, "GlobalAlloc failed!");
  214.         return;
  215.         }
  216.     b = GlobalLock (hg);
  217.  
  218.     if (dpm.encoding & PE_16BIT)
  219.         /* Convert data to signed 16-bit PCM */
  220.         s32tos16 (buf, count);
  221.     else
  222.         /* Convert to 8-bit unsigned. */
  223.         s32tou8 (buf, count);
  224.  
  225.     CopyMemory(b, buf, len);
  226.     if (play (b, len))
  227.         {
  228.         GlobalUnlock (hg);
  229.         GlobalFree (hg);
  230.         }
  231.     }
  232.  
  233. static void close_output (void)
  234.     {
  235.     wait ();
  236.     waveOutClose (dev);
  237.     }
  238.  
  239. static void flush_output (void)
  240.     {
  241.     wait ();
  242.     }
  243.  
  244. static void purge_output (void)
  245.     {
  246.     waveOutReset (dev);
  247.     wait ();
  248.     }
  249.  
  250.